/*
 * uart_io.c
 *
 *  Created on: Sep 19, 2013
 *      Author: Ken Arok
 */

#include "config_ROM.h"
#include "rom.h"
#include "uart_io.h"


/*! UART default parameter. */
#define UART_SPEED_DEFAULT				9600				//! UART baudrate default is 9600
#define UART_DATA_BITS_DEFAULT			8					//! UART data width default is 8 bits
#define UART_PARITY_DEFAULT				UART_NO_PARITY		//! UART parity default is no parity
#define UART_STOPBIT_DEFAULT			UART_1_STOPBIT		//! UART stop bit default is 1 stop bit


/* UART option parameter. */
static uart_options_t uart_opts[2];

/* Opened state of uart port.
 * 0 - closed / ready
 * 1 - opened / busy
 */
static uint8_t uart_opened_state[2] = {0, 0};


void uart_io_init(void)
{
	uint8_t _basePort, i;

	/* Initialize UART. */
	uart_init();

	/* Load UART setting from ROM */
	_basePort = (uint8_t)IOP_COM1;
	for(i = 0; i < 10; i++) {
		uart_io_ctrl((io_port_t)(_basePort - IOP_COM1), IORC_LOAD_SETTING_FROM_ROM, NULL);
		_basePort++;
	}

}


uint8_t uart_io_ctrl(io_port_t comPort, io_request_code_t reqCode, void *pValue)
{
	uint8_t _ret_status = pdPASS;
	COM_port_t _basePort;

	switch(comPort) {
		case IOP_COM1:
		case IOP_COM2:
			_basePort = comPort - IOP_COM1;
			switch(reqCode) {
				case IORC_RESTART_MODULE:
					/* Initialize UART. */
					uart_init();
				break;

				case IORC_SET_DEFAULT:
					if(uart_opened_state[_basePort] == 1) {
						uart_opts[_basePort].baudrate = UART_SPEED_DEFAULT;
						uart_opts[_basePort].charlength = UART_DATA_BITS_DEFAULT;
						uart_opts[_basePort].paritytype = UART_PARITY_DEFAULT;
						uart_opts[_basePort].stopbits = UART_STOPBIT_DEFAULT;
						uart_setup(_basePort, (const uart_options_t *)&uart_opts[_basePort]);
					}
				break;

				case IORC_LOAD_SETTING_FROM_ROM:
					if(uart_opened_state[_basePort] == 1) {
						/* Load the setting of UART from ROM. */
						uart_opts[_basePort].baudrate = vReadDWordROM((const void *)&rom_uart_speed[_basePort]);
						uart_opts[_basePort].charlength = vReadByteROM((const void *)&rom_uart_databit[_basePort]);
						uart_opts[_basePort].paritytype = vReadByteROM((const void *)&rom_uart_parity[_basePort]);
						uart_opts[_basePort].stopbits = vReadByteROM((const void *)&rom_uart_stopbit[_basePort]);
						uart_setup(_basePort, (const uart_options_t *)&uart_opts[_basePort]);
					}
				break;

				case IORC_SAVE_SETTING_TO_ROM:
					vWriteDWordROM((const void *)&rom_uart_speed[_basePort], uart_opts[_basePort].baudrate);
					vWriteByteROM((const void *)&rom_uart_databit[_basePort], uart_opts[_basePort].charlength);
					vWriteByteROM((const void *)&rom_uart_parity[_basePort], uart_opts[_basePort].paritytype);
					vWriteByteROM((const void *)&rom_uart_stopbit[_basePort], uart_opts[_basePort].stopbits);
				break;

				case IORC_SET_RX_TIMEOUT:
					if(uart_opened_state[_basePort] == 1) {
						uart_rx_timeout(_basePort, *(const uint32_t *)pValue);
					}
				break;

				case IORC_SET_SPEED:
					if(uart_opened_state[_basePort] == 1) {
						uart_opts[_basePort].baudrate = *(uint32_t *)pValue;
						uart_setup(_basePort, (const uart_options_t *)&uart_opts[_basePort]);
					}
				break;

				case IORC_SET_DATA_BIT:
					if(uart_opened_state[_basePort] == 1) {
						uart_opts[_basePort].charlength = *(uint8_t *)pValue;
						uart_setup(_basePort, (const uart_options_t *)&uart_opts[_basePort]);
					}
				break;

				case IORC_SET_TRANSFER_POLLED:
					if(uart_opened_state[_basePort] == 1) {
						uart_tranfer_mode(_basePort, UART_POLLED);
					}
				break;

				case IORC_SET_TRANSFER_POLLED_TX:
					if(uart_opened_state[_basePort] == 1) {
						uart_tranfer_mode(_basePort, UART_POLLED_TX);
					}
				break;

				case IORC_SET_TRANSFER_POLLED_RX:
					if(uart_opened_state[_basePort] == 1) {
						uart_tranfer_mode(_basePort, UART_POLLED_RX);
					}
				break;

				case IORC_SET_TRANSFER_INTERRUPT:
					if(uart_opened_state[_basePort] == 1) {
						uart_tranfer_mode(_basePort, UART_INTERRUPT);
					}
				break;

				case IORC_SET_PARITY:
					if(uart_opened_state[_basePort] == 1) {
						uart_opts[_basePort].paritytype = *(uint8_t *)pValue;
						uart_setup(_basePort, (const uart_options_t *)&uart_opts[_basePort]);
					}
				break;

				case IORC_SET_STOP_BIT:
					if(uart_opened_state[_basePort] == 1) {
						uart_opts[_basePort].stopbits = *(uint16_t *)pValue;
						uart_setup(_basePort, (const uart_options_t *)&uart_opts[_basePort]);
					}
				break;

				default:
					 _ret_status = pdFAIL;
				break;
			}
		break;

		default:
			_ret_status = pdFAIL;
		break;
	}

	return _ret_status;
}


uint8_t uart_io_open(io_port_t comPort, const uint8_t flag)
{
	uint8_t _ret_status = pdFAIL;
	COM_port_t _basePort;

	switch(comPort) {
		case IOP_COM1:
		case IOP_COM2:
			_basePort = comPort - IOP_COM1;
			if(uart_open(_basePort, flag) == UART_STATUS_OK) {
				uart_opened_state[_basePort] = 1;
				_ret_status = pdPASS;
			}
		break;

		default: break;
	}


	return _ret_status;
}


uint8_t uart_io_close(io_port_t comPort)
{
	uint8_t _ret_status = pdFAIL;
	COM_port_t _basePort;

	switch(comPort) {
		case IOP_COM1:
		case IOP_COM2:
			_basePort = comPort - IOP_COM1;
			uart_close(_basePort);
			uart_opened_state[_basePort] = 0;
			_ret_status = pdPASS;
		break;

		default: break;
	}

	return _ret_status;
}


uint8_t uart_io_write(io_port_t comPort, const void *pBuf, uint32_t size, io_rw_flag_t flag)
{
	uint8_t _ret_status = pdFAIL;
	COM_port_t _basePort;

	if(uart_opened_state[comPort] == 0) {
		return _ret_status;
	}

	switch(comPort) {
		case IOP_COM1:
		case IOP_COM2:
			_basePort = comPort - IOP_COM1;
			switch(flag) {
				case IORWF_BYTE_ORDER:
					if (uart_write_byte(_basePort, pBuf, size) == UART_STATUS_OK) {
						_ret_status = pdPASS;
					}
				break;

				case IORWF_WORD_ORDER:
					if (uart_write_word(_basePort, pBuf, size) == UART_STATUS_OK) {
						_ret_status = pdPASS;
					}
				break;

				default: break;
			}
		break;


		default: break;
	}

	return _ret_status;
}


uint32_t uart_io_read(io_port_t comPort, void *pBuf, uint32_t size, io_rw_flag_t flag)
{
	uint32_t _recv_count = 0;
	COM_port_t _basePort;

	if(uart_opened_state[comPort] == 0) {
		return _recv_count;
	}

	switch(comPort) {
		case IOP_COM1:
		case IOP_COM2:
			_basePort = comPort - IOP_COM1;
			switch(flag) {
				case IORWF_BYTE_ORDER:
					uart_read_byte(_basePort, pBuf, size, &_recv_count);
				break;

				case IORWF_WORD_ORDER:
					uart_read_word(_basePort, pBuf, size, &_recv_count);
				break;

				default: break;
			}
		break;

		default: break;
	}

	return _recv_count;
}
